import { useCallback, useRef, useState, SetStateAction } from "react";

type Options<T> = {
  defaultValue: () => T | T;
  onChange?: (v: T) => void;
};

const useUpdate = () => {
  const [, setState] = useState({});

  return useCallback(() => setState({}), []);
};

export function useRefValue<T>(
  options: Options<T>
): [
  React.MutableRefObject<T>,
  (value: SetStateAction<T>, forceUpdate?: boolean) => void
] {
  const { defaultValue, onChange } = options;
  const defaultValueIns =
    typeof defaultValue === "function" ? defaultValue() : defaultValue;
  const ref = useRef<T>(defaultValueIns);
  const update = useUpdate();

  const setValue = useCallback(
    (value: SetStateAction<T>, forceUpdate: boolean = false) => {
      const nextValue =
        typeof value === "function"
          ? (value as (prevState: T) => T)(ref.current)
          : value;
      if (!forceUpdate && nextValue === ref.current) return;
      ref.current = nextValue;
      update();
      return onChange?.(nextValue);
    },
    []
  );

  return [ref, setValue];
}
